package com.ddtech.utils;

import com.ddtech.models.BaseTreeBean;
import org.apache.commons.collections4.CollectionUtils;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author Second
 */
public class TreeUtils {

    public static <M extends BaseTreeBean<M>> List<M> buildListToTree(List<M> datas) {
        List<M> roots = findRoots(datas);
        List<M> notRoots = (List) CollectionUtils.subtract(datas, roots);
        Iterator iterator = roots.iterator();
        while (iterator.hasNext()) {
            M root = (M) iterator.next();
            List<M> children = findChildren(root, notRoots);
            root.setChildren(children);
        }
        return roots;
    }

    public static <T extends Map<String, Object>> List<T> buildListToTree(List<T> datas, String idKey, String pidKey) {
        List<T> roots = findRoots(datas, idKey, pidKey);
        List<T> notRoots = (List) CollectionUtils.subtract(datas, roots);
        Iterator iterator = roots.iterator();
        while (iterator.hasNext()) {
            T root = (T) iterator.next();
            List<T> children = findChildren(root, notRoots, idKey, pidKey);
            root.put("children", children);
        }
        return roots;
    }

    public static <T extends Map<String, Object>> List<T> findRoots(List<T> allNodes, String idKey, String pidKey) {
        return (List) allNodes.stream().filter((q) -> {
            return allNodes.stream().noneMatch((o) -> {
                return o.get(idKey).equals(q.get(pidKey));
            });
        }).collect(Collectors.toList());
    }

    public static <T extends Map<String, Object>> List<T> findChildren(T root, List<T> allNodes, String idKey, String pidKey) {
        List<T> children = (List) allNodes.stream().filter((o) -> {
            return root.get(idKey).equals(o.get(pidKey));
        }).collect(Collectors.toList());
        List<T> notChildren = (List) CollectionUtils.subtract(allNodes, children);
        Iterator iterator = children.iterator();

        while (iterator.hasNext()) {
            T child = (T) iterator.next();
            List<T> tmpChildren = findChildren(child, notChildren, idKey, pidKey);
            child.put("children", tmpChildren);
        }
        return children;
    }

    public static <M extends BaseTreeBean<M>> List<M> findRoots(List<M> allNodes) {
        return (List) allNodes.stream().filter((q) -> {
            return allNodes.stream().noneMatch((o) -> {
                return o.getIdValue().equals(q.getPidValue());
            });
        }).collect(Collectors.toList());
    }

    public static <M extends BaseTreeBean<M>> List<M> findChildren(M root, List<M> allNodes) {
        List<M> children = (List) allNodes.stream().filter((o) -> {
            return root.getIdValue().equals(o.getPidValue());
        }).collect(Collectors.toList());
        List<M> notChildren = (List) CollectionUtils.subtract(allNodes, children);
        Iterator iterator = children.iterator();

        while (iterator.hasNext()) {
            M child = (M) iterator.next();
            List<M> tmpChildren = findChildren(child, notChildren);
            child.setChildren(tmpChildren);
        }

        return children;
    }

}
